home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume6 / pathrpt < prev    next >
Encoding:
Text File  |  1989-04-23  |  23.7 KB  |  671 lines

  1. Newsgroups: comp.sources.misc
  2. From: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  3. Subject: v06i093: pathrpt -- a reporting tool companion for pathalias
  4. Reply-To: david@dhw68k.cts.com (David H. Wolfskill)
  5.  
  6. Posting-number: Volume 6, Issue 93
  7. Submitted-by: david@dhw68k.cts.com (David H. Wolfskill)
  8. Archive-name: pathrpt
  9.  
  10. I asked the folks in comp.mail.uucp if they would find a program such as
  11. this useful or helpful; the overwhelming response was "Yes!" (along with
  12. requests to mail copies).  Anyway, I think comp.sources.misc would be a
  13. better place for it than comp.sources.unix, mostly because it's not
  14. terribly sophisticated -- it's really just a little filter to accompany
  15. pathalias.
  16.  
  17. I've been using it for several months (in one form or another), and
  18. I've sent copies off to some folks.  The only reported problems I've
  19. heard with its use came from a VMS site, and I didn't understand what
  20. the problems were....
  21.  
  22. What this thing is:  pathrpt makes a report based on the output of
  23. pathalias.  The report indicates how many of the paths (from the
  24. pathalias output) start at each of your uucp neighbors.  It also gives
  25. some clue as to the lengths of those paths -- and it checks to see if
  26. the uucp maps indicate you have a neighbor you don't think you have.
  27.  
  28. The above report(s) come out on stderr, so make it easier to use the
  29. program for its other purpose in life -- taking the place of the "sed"
  30. step in the pathproc distributed with smail.  (The smail-format
  31. pathalias output comes out on stdout.)
  32.  
  33. Folks who don't run pathalias probably have no use for this program.
  34.  
  35. Thanks,
  36. david  (Wed Apr 19 07:02:55 PDT 1989)
  37.  
  38. #! /bin/sh
  39. # This is a shell archive, meaning:
  40. # 1. Remove everything above the #! /bin/sh line.
  41. # 2. Save the resulting text in a file.
  42. # 3. Execute the file with /bin/sh (not csh) to create the files:
  43. #    pathrpt.c
  44. # This archive created: Wed Apr 19 06:47:00 1989
  45. export PATH; PATH=/bin:$PATH
  46. echo shar: extracting "'pathrpt.c'" '(20748 characters)'
  47. if test -f 'pathrpt.c'
  48. then
  49.     echo shar: will not over-write existing file "'pathrpt.c'"
  50. else
  51. sed 's/^    X//' << \SHAR_EOF > 'pathrpt.c'
  52.     X/*
  53.     X *
  54.     X * This program is Copyright 1989, by David H. Wolfskill.
  55.     X *
  56.     X * Anyone may freely copy it and use it for any purpose, as long as:
  57.     X * 1) it is not sold, and
  58.     X * 2) no one else attempts to claim authorship of the program.
  59.     X * (In all humility and honesty, I can't imagine why anyone would want to do
  60.     X * either of the above, but human nature is a truly marvelous thing....)
  61.     X *
  62.     X * [First part of above is freely adapted from "rn," by Larry Wall.... dhw]
  63.     X *
  64.     X * Disclaimer: Although the author finds the program useful, there is no
  65.     X *             guarantee that anyone else will find it useful for any given
  66.     X *             purpose.  Caveat Emptor, and all that.
  67.     X *             
  68.     X * I cannot, of course, promise to fix things that some folks may think are
  69.     X * broken; nor can I promise to implement enhancements.  However, I have a
  70.     X * strong desire to do what I can to help improve email, especially over dialup
  71.     X * 'phone lines; accordingly, it is my present intent to support this program
  72.     X * as a tool that can be helpful in some circumstances... as long as what it
  73.     X * reports isn't trusted too much....  :-)
  74.     X *
  75.     X * In all seriousness, comments & suggestions may be sent to me via
  76.     X *
  77.     X * InterNet: david@dhw68k.cts.com
  78.     X * uucp: ...{spsd,zardoz,felix}!dhw68k!david    
  79.     X *
  80.     X * and -- unless you have been explicitly informed otherwise by someone
  81.     X * in a position to know (such as me) -- I welcome suggestions for improvement.
  82.     X *
  83.     X * David H. Wolfskill    16 April, 1989
  84.     X *
  85.     X */
  86.     X
  87.     X/*
  88.     X *    Program to list statistics, some of which may be of interest,
  89.     X *    regarding the output of "pathalias," as well as do a basic
  90.     X *    "reality check" on that output.
  91.     X
  92.     X *    By its nature, this program is intended to be used in conjunction
  93.     X *    with pathalias.  I really don't think you should spend any time
  94.     X *    or other resources on this program if you neither run nor have
  95.     X *    any intent to run pathalias.
  96.     X
  97.     X *    This version can read the pathalias output either in the
  98.     X *    original order, or either of the 2 rotations:
  99.     X
  100.     X *    "pathalias":    <cost>    <destination>    <path>
  101.     X *    "smail":    <destination>    <path>    <cost>
  102.     X *    unknown:    <path>    <cost>    <destination>
  103.     X
  104.     X *    It does *not* (presently) handle "<destination>    <cost>    <path>"
  105.     X *    (or any of its rotations); if you really think it's something
  106.     X *    worth doing, I'm willing to discuss it further, but really...!
  107.     X
  108.     X *    In order to make the determination of the stdin format, the
  109.     X *    first line is read, and its 3 fields are scanned to find one
  110.     X *    that ends in "%s".  If no such field is found, the program
  111.     X *    claims that the input is not pathalias output, and exits.  If
  112.     X *    one *is* found, however (the normal case, we hope!), that field
  113.     X *    is assumed to be the <path> field; the next field (to the right,
  114.     X *    wrapping around if necessary) is the <cost>, and the next is
  115.     X *    <destination>.
  116.     X
  117.     X *    smail likes the second order, so the stdout of this program
  118.     X *    is the same information in "smail" order (regardless of the
  119.     X *    order in which stdin is).  This program may thus be used in
  120.     X *    place of the "sed" segment of the "pathproc" pipeline that is
  121.     X *    distributed with smail.
  122.     X
  123.     X *    To facilitate its use in that application, the report the
  124.     X *    program generates comes out on stderr.
  125.     X
  126.     X *    The overall method is straightforward, brute-force:  uuname (or
  127.     X *    whatever -- see macro NBRLIST) is used to generate a list of
  128.     X *    known immediate uucp neighbors; that is run through sort.  (I
  129.     X *    do it this way because uuname is set[gu]id; I think it
  130.     X *    appropriate to minimize the need for programs to run as
  131.     X *    set[gu]id, so I use the facilities provided by a common tool,
  132.     X *    rather than require special privileges for this program.)  Then
  133.     X *    a "neighbor" (spelled "nbr" for typing constraint relief)
  134.     X *    struct is allocated for each neighbor thus found -- after one
  135.     X *    of these structs is allocated for the totals.  The nbr structs
  136.     X *    are allocated as a linked list.  (A temporary file is created
  137.     X *    to hold the output of sort; after the nbr structs are all
  138.     X *    allocated, it is unlinked and closed.)
  139.     X
  140.     X *    Once this housekeeping is finished, a single pass through stdin
  141.     X *    (which is expected to be in the above-documented -- possibly
  142.     X *    rotated -- pathalias output format) is made, updating the
  143.     X *    appropriate counters in the various nbr structs:  the "tots"
  144.     X *    nbr struct is always updated; the "first hop" in the path is
  145.     X *    determined, and the nbr struct that corresponds to it is also
  146.     X *    updated.
  147.     X
  148.     X *    A <path> field that consists entirely of "%s" is assumed to
  149.     X *    have a "first hop" of the local host.  The program will
  150.     X *    determine this by using the -l flag (ala' pathalias); if -l was
  151.     X *    not specified, routine hostname() is invoked, which either uses
  152.     X *    uname() (if UNAME is defined during compilation) or
  153.     X *    gethostname() (if it wasn't).  If hostname() is invoked and
  154.     X *    fails, the program complains bitterly and exits -- in such a
  155.     X *    case, you may wish to change the logic in hostname() or specify
  156.     X *    the -l flag, depending on how ambitious you are.
  157.     X
  158.     X *    For a <path> field that is more than "%s", everything from the
  159.     X *    beginning of the field up to (but not including) the first
  160.     X *    occurrence of '!' is assumed to be the name of the "first hop"
  161.     X *    -- which ought to be the name of one of the specified host's
  162.     X *    neighbors.
  163.     X
  164.     X *    (Note the pathological case of the pathalias output claiming
  165.     X *    the existence of a neighbor that NBRLIST doesn't know about.
  166.     X *    That actually happened in the early testing of the program, and
  167.     X *    as a result of that experience, I put in code to create a "nbr"
  168.     X *    struct on demand (as it were) in such a case, then in the
  169.     X *    output phase, spit out a warning message.)
  170.     X
  171.     X *    Once EOF is reached on stdin, a pair of traversals through the
  172.     X *    linked list is made; each prints a report based on the
  173.     X *    accumulated totals, and the second one also frees the elements
  174.     X *    of the list.  The second report shows a distribution of how
  175.     X *    long the paths are; its width -- how far out to count distinct
  176.     X *    pathlengths -- is controlled by the MAXDIST macro and the -d
  177.     X *    flag.
  178.     X
  179.     X *    Then we're done -- what could be simpler...?  :-)
  180.     X
  181.     X
  182.     X
  183.     X *    Notes about the flags:
  184.     X
  185.     X *    Since the program was first written, the number of flags
  186.     X *    ("command line arguments" for picky folk) has become large;
  187.     X *    herewith is a list of them:
  188.     X
  189.     X *    -B <limit>      <limit> specifies an OUTPUT limit: if the
  190.     X *            cost to reach a destination is below the
  191.     X *            specified limit, the stdout will not contain
  192.     X *            that line of input data.  To make this flag
  193.     X *            ineffective, use a value of 0.  Default is
  194.     X *            BOTOUT (0).
  195.     X
  196.     X *    -T <limit>      <limit> specifies an OUTPUT limit: if the
  197.     X *            cost to reach a destination is above the
  198.     X *            specified limit, the stdout will not contain
  199.     X *            that line of input data.  To make this flag
  200.     X *            ineffective, use a value of 0.  Default is
  201.     X *            TOPOUT (0).
  202.     X
  203.     X *    -b <limit>    <limit> specifies a REPORTING limit: if the
  204.     X *            cost to reach a destination is below the
  205.     X *            specified limit, the reports (on stderr) will
  206.     X *            not reflect that line of input data.  To make
  207.     X *            this flag ineffective, use a value of 0.
  208.     X *            Default is BOTCNT (0).
  209.     X
  210.     X *    -t <limit>    <limit> specifies a REPORTING limit: if the
  211.     X *            cost to reach a destination is above the
  212.     X *            specified limit, the reports (on stderr) will
  213.     X *            not reflect that line of input data.  To make
  214.     X *            this flag ineffective, use a value of 0.
  215.     X *            Default is TOPCNT (0).
  216.     X
  217.     X *    -d <dist>    <dist> specifies the number of "distribution
  218.     X *            buckets" for the 2nd report -- the one that
  219.     X *            (sort of) shows a "histogram" of the hopcounts
  220.     X *            of the paths to each of the neighboring sites.
  221.     X *            The default value is DDIST (20).
  222.     X
  223.     X *    -l <host>    <host> specifies a local hostname other than
  224.     X *            the default; it is intended to be similar in
  225.     X *            operation to the pathalias flag of similar name
  226.     X *            and intent.
  227.     X
  228.     X *    -z         specifies that the reports are not to include
  229.     X *            lines for neighboring sites that are not "first
  230.     X *            hops" in the stdin.
  231.     X
  232.     X *    Note that each of the flags is completely independent of any
  233.     X *    other flag -- and that some combinations are (arguably) useful,
  234.     X *    while some are misleading or dangerous.
  235.     X
  236.     X *    In the normal course of the use of the program, it is expected
  237.     X *    that it will be executed in a shell script, so once the flags
  238.     X *    have been figured out, this should be substantially less of a
  239.     X *    burden than typing all that stuff....  Of course, the defaults
  240.     X *    for each of the -b, -t, -B, -T, and -d flags can be compiled
  241.     X *    in, too....
  242.     X
  243.     X */
  244.     X
  245.     X
  246.     X
  247.     X#include <stdio.h>
  248.     X#include <string.h>
  249.     X
  250.     X#ifndef    MAXLINE
  251.     X#define    MAXLINE    256    /* Assumed maximum field length from input */
  252.     X#endif    MAXLINE
  253.     X
  254.     X#ifndef    ERRLEN
  255.     X#define    ERRLEN    256    /* Assumed maximum line length for error message */
  256.     X#endif    ERRLEN
  257.     X
  258.     X#ifndef    HOSTLEN
  259.     X#define    HOSTLEN    128    /* Assumed maximum length for host name */
  260.     X#endif    HOSTLEN
  261.     X
  262.     X#ifndef    SYSLEN
  263.     X#define    SYSLEN    80    /* Assumed maximum length for "system (2)" call */
  264.     X#endif    SYSLEN
  265.     X
  266.     X#ifndef    NBRLIST
  267.     X#ifdef    UNAME
  268.     X#define    NBRLIST    "(uuname -l;uuname) | sort"    /* Command for list of hosts */
  269.     X#else    /*  !UNAME  */
  270.     X#define    NBRLIST    "(hostname;uuname) | sort"    /* Command for list of hosts */
  271.     X#endif    /* UNAME */
  272.     X#endif    NBRLIST
  273.     X
  274.     X#ifndef    MAXDIST
  275.     X#define    MAXDIST    20    /* max # "buckets" for pathlength distribution chart */
  276.     X#endif    MAXDIST
  277.     X
  278.     X#ifndef    DDIST
  279.     X#define    DDIST    MAXDIST    /* default # "buckets" for pathlength distribution chart */
  280.     X#endif    DDIST
  281.     X
  282.     X#ifndef    STRCHR
  283.     X#define    STRCHR    strchr    /* strchr() or index() function */
  284.     X#endif    STRCHR
  285.     X
  286.     X#ifndef    DEAD
  287.     X#define    DEAD    30000000    /* Intended to match the pathalias value */
  288.     X#endif    DEAD
  289.     X
  290.     X#ifndef    TOPOUT
  291.     X#define    TOPOUT    0    /* "0" == don't supress any output; !0 == threshhold */
  292.     X#endif    TOPOUT
  293.     X
  294.     X#ifndef    BOTOUT
  295.     X#define    BOTOUT    0    /* "0" == don't supress any output; !0 == threshhold */
  296.     X#endif    BOTOUT
  297.     X
  298.     X#ifndef    TOPCNT
  299.     X#define    TOPCNT    0    /* "0" == don't supress any output; !0 == threshhold */
  300.     X#endif    TOPCNT
  301.     X
  302.     X#ifndef    BOTCNT
  303.     X#define    BOTCNT    0    /* "0" == don't supress any output; !0 == threshhold */
  304.     X#endif    BOTCNT
  305.     X
  306.     Xstruct nbr {        /* struct for "neighbor" host                 */
  307.     X    struct nbr *next;    /* pointer to next neighbor on the list       */
  308.     X    char    *host;        /* name of neighboring host                   */
  309.     X    int    firsthop;    /* count of times this appears as "1st hop"   */
  310.     X    int    hopcount;    /* sum of path lengths that start here        */
  311.     X    int    pthlng[MAXDIST];    /* buckets for pathlength dist.       */
  312.     X    double    cost;        /* sum of COSTS for paths that start here     */
  313.     X};
  314.     X
  315.     Xint    main(argc, argv)  /* find interesting statistics about a "paths" file */
  316.     Xint    argc;
  317.     Xchar    *argv[];
  318.     X
  319.     X{
  320.     X    struct nbr *tots;    /* "pseudo-neighbor" for totals               */
  321.     X    struct nbr *tnbr;    /* temporary pointer to a "nbr" struct        */
  322.     X    struct nbr *lnbr;    /* pointer to last-allocated "nbr" struct     */
  323.     X    struct nbr *bnbr;    /* pointer to first "bad" "nbr" struct        */
  324.     X    struct nbr *getnbr();    /* routine to create a new nbr struct */
  325.     X
  326.     X    extern int    errno;        /* used by perror() and friends       */
  327.     X    extern int    optind;        /* for getopt()                  */
  328.     X    extern char    *optarg;    /* for getopt()                  */
  329.     X
  330.     X    char    *tempnam();    /* function to generate name of work file     */
  331.     X    char    *tmpf;        /* points to pathname of temporary file       */
  332.     X    FILE    * tf;        /* FILE pointer for temporary file            */
  333.     X
  334.     X    char    sys[SYSLEN];    /* command line used to get list of neighbors */
  335.     X
  336.     X    char    *hostname();    /* function to go find out where I am         */
  337.     X    char    site[HOSTLEN];    /* char array to hold name of site            */
  338.     X
  339.     X    char    str[3][MAXLINE];/* input strings for pathalias output         */
  340.     X    int    field;        /* index for str[][] array                    */
  341.     X    int    strl;        /* length of str[][] array                    */
  342.     X    char    *dest;        /* used for both "destination" and "1st hop"  */
  343.     X    char    *path;        /* string for uucp "path" to get to dest      */
  344.     X    char    *scost;        /* pointer to cost data in string form        */
  345.     X    double    cost;        /* pathalias "COST" to get to a given dest    */
  346.     X
  347.     X    int    top_out;    /* controls high end of output suppression    */
  348.     X    int    bot_out;    /* controls low end of output suppression     */
  349.     X    int    top_cnt;    /* controls high end of counting              */
  350.     X    int    bot_cnt;    /* controls low end of counting               */
  351.     X    int    zflag;        /* controls reporting neighbors w/ 0 paths    */
  352.     X
  353.     X    int    error;        /* "error" flag returned by program           */
  354.     X    int    hops;        /* number of "hops" to get to given dest      */
  355.     X    int    dist;        /* number of "buckets" for pathlength distr.  */
  356.     X    int    ch;        /* garden-variety character/EOF-holder        */
  357.     X    char    *name;        /* name of program -- as invoked, for msgs    */
  358.     X    char    errmsg[ERRLEN];    /* string for constructing error messages     */
  359.     X    char    *chptr;        /* garden-variety pointer-to-char work var    */
  360.     X
  361.     X    name = argv[0];
  362.     X    error = 0;
  363.     X    dist = DDIST;
  364.     X    bnbr = NULL;
  365.     X    site[0] = 0;
  366.     X    top_out = TOPOUT;
  367.     X    bot_out = BOTOUT;
  368.     X    top_cnt = TOPCNT;
  369.     X    bot_cnt = BOTCNT;
  370.     X    zflag = 1;
  371.     X
  372.     X    while ((ch = getopt(argc, argv, "b:B:d:l:t:T:z")) != EOF)
  373.     X        switch (ch) {
  374.     X        case 'B':
  375.     X            (void)sscanf(optarg, "%d", &bot_out);
  376.     X            break;
  377.     X        case 'b':
  378.     X            (void)sscanf(optarg, "%d", &bot_cnt);
  379.     X            break;
  380.     X        case 'd':
  381.     X            (void)sscanf(optarg, "%d", &dist);
  382.     X            break;
  383.     X        case 'l':
  384.     X            if (strlen(optarg) < HOSTLEN) 
  385.     X                (void)strcpy(site, optarg);
  386.     X            else     {
  387.     X                (void)strncpy(site, optarg, HOSTLEN - 1);
  388.     X                site[HOSTLEN-1] = 0;
  389.     X            }
  390.     X            break;
  391.     X        case 'T':
  392.     X            (void)sscanf(optarg, "%d", &top_out);
  393.     X            break;
  394.     X        case 't':
  395.     X            (void)sscanf(optarg, "%d", &top_cnt);
  396.     X            break;
  397.     X        case 'z':
  398.     X            zflag = 0;
  399.     X            break;
  400.     X        default:
  401.     X            (void)fprintf(stderr, "usage: %s -d dist -l host -b limit -B limit -t limit -T limit -z\n", name);
  402.     X            exit(error = 1);
  403.     X        }
  404.     X
  405.     X    if ((site[0] == 0) && (hostname(site) == NULL)) {
  406.     X        (void)sprintf(errmsg, "%s: hostname() failed", name);
  407.     X        (void)perror(errmsg);
  408.     X        exit(error = errno);
  409.     X    }
  410.     X
  411.     X    dist = dist > MAXDIST ? MAXDIST : dist;
  412.     X
  413.     X    if ((tots = tnbr = getnbr("TOTALS")) == NULL) {
  414.     X        (void)sprintf(errmsg, "%s: getnbr(\"TOTALS\") failed", name);
  415.     X        (void)perror(errmsg);
  416.     X        exit(error = errno);
  417.     X    }
  418.     X
  419.     X    tmpf = tempnam((char *)NULL, (char *)NULL);
  420.     X    (void)sprintf(sys, "%s >%s", NBRLIST, tmpf);
  421.     X    (void)system(sys);
  422.     X
  423.     X    if ((tf = fopen(tmpf, "r")) == NULL) {
  424.     X        (void)sprintf(errmsg, "%s: fopen(%s, \"r\") failed", name, tmpf);
  425.     X        (void)perror(errmsg);
  426.     X        exit(error = errno);
  427.     X    }
  428.     X
  429.     X    while (fscanf(tf, "%s", str[0]) != EOF) {
  430.     X        if ((tnbr->next = getnbr(str[0])) == NULL) {
  431.     X            (void)sprintf(errmsg, "%s: getnbr(%s) failed", name, str[0]);
  432.     X            (void)perror(errmsg);
  433.     X            exit(error = errno);
  434.     X        }
  435.     X        tnbr = tnbr->next;
  436.     X    }
  437.     X
  438.     X    if (unlink(tmpf) != 0) {
  439.     X        (void)sprintf(errmsg, "%s: unlink(%s) failed", name, tmpf);
  440.     X        (void)perror(errmsg);
  441.     X        exit(error = errno);
  442.     X    }
  443.     X
  444.     X    if (fclose(tf) == EOF) {
  445.     X        (void)sprintf(errmsg, "%s: fclose(tf) failed", name);
  446.     X        (void)perror(errmsg);
  447.     X        exit(error = errno);
  448.     X    }
  449.     X
  450.     X    if (scanf("%s%s%s", &str[0][0], &str[1][0], &str[2][0]) != EOF) {
  451.     X        for (field = 0; field < 3; field++) {
  452.     X            if ((strl = strlen(str[field])) > 1) {
  453.     X                if (strcmp(&str[field][strl-2], "%s") == 0)
  454.     X                    break;
  455.     X            }
  456.     X        }
  457.     X        if (field > 2) {
  458.     X            (void)fprintf(stderr, "%s: input is not pathalias format\n", name);
  459.     X            exit(error = field);
  460.     X        }
  461.     X        path = &str[field++][0];
  462.     X        scost = &str[(field++)%3][0];
  463.     X        dest = &str[(field++)%3][0];
  464.     X
  465.     X        do {
  466.     X            (void)sscanf(scost, "%lg", &cost);
  467.     X            if ((bot_out <= cost) && ((top_out == 0) || (top_out >= cost)))
  468.     X                (void)printf("%s\t%s\t%s\n", dest, path, scost);
  469.     X            if ((bot_cnt <= cost) && ((top_cnt == 0) || (top_cnt >= cost))) {
  470.     X                tots->firsthop++;
  471.     X                tots->cost += cost;
  472.     X                chptr = path;
  473.     X                hops = strcspn(path, "!");
  474.     X                (void)strncpy(dest, path, hops);    /* save name of "first hop" */
  475.     X                *(dest + hops) = 0;        /* ensure proper null term. */
  476.     X
  477.     X                hops = 0;
  478.     X                while ((chptr = STRCHR(chptr, '!')) != NULL) {
  479.     X                    chptr++;
  480.     X                    hops++;
  481.     X                }
  482.     X
  483.     X                tots->hopcount += hops;
  484.     X                tots->pthlng[hops<dist?hops:dist-1]++;
  485.     X                if (hops == 0 && strcmp(dest, "%s") == 0) 
  486.     X                    (void)strcpy(dest, site);
  487.     X
  488.     X                if (tnbr->next == NULL) 
  489.     X                    tnbr = tots;
  490.     X                if ((strcmp(dest, tnbr->next->host)) != 0) {
  491.     X                    tnbr = tots;
  492.     X                    while ((tnbr->next != NULL) && (strcmp(dest, tnbr->next->host)) != 0)
  493.     X                        tnbr = tnbr->next;
  494.     X                }
  495.     X
  496.     X                if (tnbr->next == NULL) {
  497.     X                    if ((lnbr = getnbr(dest)) == NULL) {
  498.     X                        (void)sprintf(errmsg, "%s: getnbr(%s) failed", name, dest);
  499.     X                        (void)perror(errmsg);
  500.     X                        exit(error = errno);
  501.     X                    }
  502.     X                    tnbr->next = lnbr;
  503.     X                    if (bnbr == NULL) 
  504.     X                        bnbr = lnbr;
  505.     X                }
  506.     X
  507.     X                tnbr->next->firsthop++;
  508.     X                tnbr->next->cost += cost;
  509.     X                tnbr->next->hopcount += hops;
  510.     X                tnbr->next->pthlng[hops<dist?hops:dist-1]++;
  511.     X            }
  512.     X
  513.     X        } while (scanf("%s%s%s", &str[0][0], &str[1][0], &str[2][0]) != EOF);
  514.     X    }
  515.     X
  516.     X    (void)fprintf(stderr, "\n Adj              Total         Total   #Hops        Cost");
  517.     X    (void)fprintf(stderr, "\nSite       #Dest  #Hops          Cost   /Dest       /Dest\n");
  518.     X
  519.     X    lnbr = tots;
  520.     X    while (tots != NULL) {
  521.     X        if (bnbr == tots)
  522.     X            (void)fprintf(stderr, "\n *** WARNING! Bogus \"neighbor\" sites follow! ***\n");
  523.     X        if (zflag | tots->firsthop)
  524.     X            (void)fprintf(stderr, "%-9s% 7d% 7d% 14.0f% 8.2f% 12.2f\n", tots->host,
  525.     X                tots->firsthop, tots->hopcount, tots->cost,
  526.     X                tots->firsthop ? (double)tots->hopcount / tots->firsthop : (double)0,
  527.     X                tots->firsthop ? (double)tots->cost / tots->firsthop : (double)0);
  528.     X        tots = tots->next;
  529.     X    }
  530.     X
  531.     X    tots = lnbr;
  532.     X    (void)fprintf(stderr, "\n Adj               #Hops       --- Pathlength Distribution ---");
  533.     X    (void)fprintf(stderr, "\nSite       #Dest   /Dest");
  534.     X    for (hops = 0; hops < dist; hops++) 
  535.     X        (void)fprintf(stderr, "% 5d", hops);
  536.     X    (void)fprintf(stderr, "+\n");
  537.     X
  538.     X    while (tots != NULL) {
  539.     X        if (bnbr == tots)
  540.     X            (void)fprintf(stderr, "\n *** WARNING! Bogus \"neighbor\" sites follow! ***\n");
  541.     X        if (zflag | tots->firsthop) {
  542.     X            (void)fprintf(stderr, "%-9s% 7d% 8.2f", tots->host,
  543.     X                tots->firsthop,
  544.     X                tots->firsthop ? (double)tots->hopcount / tots->firsthop : (double)0);
  545.     X            for (hops = 0; hops < dist; hops++) 
  546.     X                (void)fprintf(stderr, "% 5d", tots->pthlng[hops]);
  547.     X            (void)fprintf(stderr, "\n");
  548.     X        }
  549.     X        if (tots->host != NULL) 
  550.     X            (void)free((char *)tots->host);
  551.     X        tnbr = tots->next;
  552.     X        (void)free((char *)tots);
  553.     X        tots = tnbr;
  554.     X    }
  555.     X    exit(error);
  556.     X}
  557.     X
  558.     X
  559.     X
  560.     X
  561.     X/*
  562.     X *    This routine is given the name of a neighbor host ("nbrname"),
  563.     X *    then uses malloc() to acquire storage for a new "nbr" struct for
  564.     X *    that host.  It then uses malloc() again, this time to acquire
  565.     X *    enough storage for a copy of the nbrname, initializes that copy
  566.     X *    from the nbrname given, & anchors the nbrname in the newly-created
  567.     X *    nbr struct.
  568.     X
  569.     X *    Lastly, a pointer to the (newly-created) nbr struct is returned.
  570.     X
  571.     X *    If anything goes wrong during this, NULL is returned in lieu of a
  572.     X *    valid pointer to a nbr struct -- and any storage acquired in the
  573.     X *    process is freed.  (That is, there is a concious attempt to "back
  574.     X *    out" cleanly.)
  575.     X */
  576.     X
  577.     Xstruct nbr *(getnbr(nbrname)
  578.     X)
  579.     Xchar    *nbrname;
  580.     X
  581.     X{
  582.     X
  583.     X    char    *malloc();    /* to make lint less unhappy              */
  584.     X
  585.     X    extern int    errno;        /* used by perror() and friends       */
  586.     X
  587.     X    struct nbr *tnbr;    /* temporary anchor for new nbr struct        */
  588.     X    int    hops;        /* subscript for pathlength buckets           */
  589.     X
  590.     X    if ((tnbr = (struct nbr *)malloc((unsigned)sizeof(struct nbr))) == NULL) {
  591.     X        return((struct nbr *)NULL);
  592.     X    }
  593.     X    if ((tnbr->host = (char *)malloc((unsigned)(1 + strlen(nbrname)))) == NULL) {
  594.     X        (void)free((char *)tnbr);
  595.     X        return((struct nbr *)NULL);
  596.     X    }
  597.     X
  598.     X    tnbr->next = NULL;
  599.     X    (void)strcpy(tnbr->host, nbrname);
  600.     X    tnbr->firsthop = 0;
  601.     X    tnbr->hopcount = 0;
  602.     X    tnbr->cost = 0;
  603.     X    for (hops = 0; hops < MAXDIST; hops++) 
  604.     X        tnbr->pthlng[hops] = 0;
  605.     X    return(tnbr);
  606.     X}
  607.     X
  608.     X
  609.     X
  610.     X
  611.     X/*
  612.     X *    This routine is called to find the name of the host from whose
  613.     X *    perspective the pathalias data was created.
  614.     X
  615.     X *    Unfortunately, I do not know of a way to ensure consistency in
  616.     X *    this respect; I have tried to make consistency easy to accomplish,
  617.     X *    however, by providing the same mechanism pathalias uses to determine
  618.     X *    the name of the current host -- including the use of the l flag.
  619.     X
  620.     X *    (Thus, this routine isn't invoked if the l flag is specified when
  621.     X *    the program is invoked.)
  622.     X
  623.     X *    [The following source is basically plagiarized from the sources for
  624.     X *    pathalias.  I hope that neither Peter Honeyman nor Steve Bellovin
  625.     X *    mind too much.... dhw]
  626.     X
  627.     X *    Anyway, if a problem occurs, NULL is returned.
  628.     X */
  629.     X
  630.     Xchar    *hostname(nmptr)
  631.     Xchar    *nmptr;
  632.     X
  633.     X{
  634.     X
  635.     X    extern int    errno;        /* used by perror() and friends               */
  636.     X
  637.     X#ifdef    UNAME
  638.     X#include <sys/utsname.h>
  639.     X
  640.     X    int    uname();    /* system call to find out where I am         */
  641.     X    struct utsname ustrct;    /* utsname struct for uname()                 */
  642.     X
  643.     X    if (uname(&ustrct) < 0) 
  644.     X        return(NULL);
  645.     X    else {
  646.     X        (void)strcpy(nmptr, ustrct.nodename);
  647.     X
  648.     X#else    /*  !UNAME  */
  649.     X#include <sys/param.h>
  650.     X
  651.     X    int    gethostname();    /* system call to find out where I am         */
  652.     X    char    name[MAXHOSTNAMELEN];    /* array to hold the host name        */
  653.     X
  654.     X    if (gethostname(name, (int)MAXHOSTNAMELEN) < 0) 
  655.     X        return(NULL);
  656.     X    else {
  657.     X        (void)strcpy(nmptr, name);
  658.     X#endif    /* UNAME */
  659.     X        return(nmptr);
  660.     X    }
  661.     X
  662.     X}
  663. SHAR_EOF
  664. if test 20748 -ne "`wc -c < 'pathrpt.c'`"
  665. then
  666.     echo shar: error transmitting "'pathrpt.c'" '(should have been 20748 characters)'
  667. fi
  668. fi # end of overwriting check
  669. #    End of shell archive
  670. exit 0
  671.